In [1]:
import sys, os
parentPath = os.path.abspath('..')
if not parentPath in sys.path:
    sys.path.append(parentPath)
from presentation import hide_code_button
hide_code_button()
In [2]:
import pandas as pd
import numpy as np

import analysis
from presentation import markprint
from functools import partial
events_annotate = partial(analysis.events_annotate, region = 'vic')
average = analysis.average

%matplotlib inline
In [3]:
frm = analysis.make_dataFrm('mel', dropna = True)
cases = analysis.make_casesFrm()
In [4]:
avStay = average(frm, 'stay')
rollingAvStay = avStay.rolling(7).mean().dropna()

stayScoreAv = average(frm, 'stayscore')

rollingScores = frm.reset_index().set_index(['date', 'name'])['stayscore'].rolling(7).mean()
maxDate = rollingScores.index.get_level_values('date').max()
lgaScores = pd.DataFrame(rollingScores.loc[maxDate]).reset_index()
lgaScores = lgaScores.rename(dict(stayscore = 'Score', name = 'LGA'), axis = 1)
lgaScores = lgaScores.set_index('LGA')
bestFive, worstFive = lgaScores.nlargest(5, 'Score'), lgaScores.nsmallest(5, 'Score')

Melbourne mobility report

These plots, based on Facebook location tracking data, show the changes in patterns of movement of tense of thousands of Facebook users in response to the COVID-19 pandemic. The data has been aggregated to Local Government Areas, typically city councils.

The stay-put quantity reflects the number of records provided by Facebook which show people moving beyond their immediate vicinity (about one kilometre in any direction). The population-weighted average stay-put quantity has been plotted along with a seven-day rolling average, which smooths out daily variations. The horizontal axes are given in weeks starting Sundays.

Because of privacy concerns, Facebook's data is aggressively pruned wherever population counts are low, which leads to serious underestimates of movement for less densely populated areas. To correct this we have created a stay-put score, which normalises every value based off the averages of the best and worst three values observed for that day of the week for that council. A score of one or higher indicates that people are equalling or exceeding their best ever stay-at-home behaviours. A score of zero or lower indicates that people are matching or trailing their worst ever behaviours. A weighted average stay-put score has been plotted, as well as the complete data for all councils below it.

For comparison, the new daily cases have been plotted at the bottom, while letter annotations correspond to the major changes in public perceptions and policies, as well as public holidays.

Full data, additional aggregations, and interactive plots are available on the website. The data are updated daily and the portal is continually being improved. If you have questions or suggestions, please contact Rohan Byrne.

This work is a collaboration with Professor Sally Cripps, Dr Roman Marchant, and Dr Vincent Chin of the DARE Centre and Rohan Byrne of the University of Melbourne with funding from the Australian Research Council (FT140101266).

In [5]:
from window.plot import Canvas, Data

markprint('## Summary')

markprint('---')

ax = Canvas(size = (12, 3)).make_ax()
ax.set_title('Stay-put ratio: inner-metro average with 7-day rolling average')
ax.line(
    avStay.index,
    Data(avStay.values, lims = (0.93, 1.), capped = (True, True)),
    )
ax.line(
    Data(rollingAvStay.index, label = 'Date'),
    Data(rollingAvStay.values, label = 'Proportion staying put', lims = (0.93, 1.), capped = (True, True)),
    )
table = events_annotate(ax, avStay)
markprint(table)
markprint('---')
display(ax.canvas.fig)

markprint('---')

ax = Canvas(size = (12, 3)).make_ax()
ax.set_title('Stay-put score: inner-metro average')
ax.line(
    Data(stayScoreAv.index, label = 'Date'),
    Data(stayScoreAv.values, label = 'Average stay-put score', lims = (-1., 2.)),
    )
keystr = events_annotate(ax, stayScoreAv)
display(ax.canvas.fig)

markprint('---')

ax = Canvas(size = (12, 3)).make_ax()
ax.set_title('Stay-put score: inner-metro LGAs')
xs, ys = [], []
for name in sorted(set(frm['name'])):
    subFrm = frm.loc[frm['name'] == name]
    series = subFrm.reset_index().set_index('date')['stayscore']
    series = series.dropna()
    xs.append(Data(series.index, label = 'Date'))
    ys.append(Data(series.values, label = 'Stay-put score', lims = (-1., 2.)))
ax.multiline(xs, ys)
axPoints = frm.reset_index().groupby('date')['stayscore'].apply(max)
keystr = events_annotate(ax, axPoints)
ax.ax.legend(
    sorted(set(frm['name'])),
    loc = 'upper center',
#     bbox_to_anchor = (0.5, -0.5),
#     ncol = 5,
    bbox_to_anchor = (0.26, 0.43),
    ncol = 3,
    prop = dict(size = 8),
    fancybox = True,
    shadow = True,
    )
display(ax.canvas.fig)

markprint('---')

ax = Canvas(size = (12, 3)).make_ax()
ax.set_title('Victorian daily active cases since the second wave')
sumCases = cases.groupby(cases.index.get_level_values('date'))['active'].sum()
ax.line(
    Data(sumCases.index, label = 'Date'),
    Data(sumCases.values, label = 'Active cases'),
    )
display(ax.canvas.fig)

markprint('---')

Summary


Key Event
a First lockdown begins
b Good Friday
c Easter; State of emergency extended
d School term begins
e ANZAC Day
f Testing blitz announced
g First lockdown ends
h Easing plan revealed
i 'Stay-safe' message softening
j 'Reasons to leave' message softening
k Cafes reopen
l Black Lives Matter protests
m Queen's Birthday
n Further easing revealed
o Easing halted
p Hot-spot testing blitz
q School holidays begin
r Hot-spot lockdown
s Tower lockdown
t City lockdown announced
u City lockdown in effect
v Face covering recommended
w Senior schools return
x Police crackdown announced
y Regional escalation
z Face covering announced
aa All schools return





In [6]:
markprint("### Average scores for the past week per LGA:")
display(lgaScores)
markprint("#### Best five:")
display(bestFive)
markprint("#### Worst five:")
display(worstFive)

Average scores for the past week per LGA:

Score
LGA
Bayside 0.419789
Boroondara 0.428567
Brimbank 0.446701
Casey 0.428159
Glen Eira 0.423835
Greater Dandenong 0.406476
Hume 0.387288
Kingston 0.342774
Maribyrnong 0.314526
Melbourne 0.350677
Moonee Valley 0.382557
Moreland 0.401601
Port Phillip 0.437225
Stonnington 0.478962
Yarra 0.541001

Best five:

Score
LGA
Yarra 0.541001
Stonnington 0.478962
Brimbank 0.446701
Port Phillip 0.437225
Boroondara 0.428567

Worst five:

Score
LGA
Maribyrnong 0.314526
Kingston 0.342774
Melbourne 0.350677
Moonee Valley 0.382557
Hume 0.387288
In [7]:
markprint('## Breakdown by LGA')

for name in sorted(set(frm['name'])):

    markprint(f'### {name}')

    subFrm = frm.loc[frm['name'] == name]
    subFrm = subFrm.reset_index().set_index('date')
    subStay = subFrm['stay'].dropna()
    rollingSubStay = subStay.rolling(7).mean().dropna()
    subScore = subFrm['stayscore'].dropna()

    ax = Canvas(size = (12, 3)).make_ax()
    ax.set_title('Stay-put ratio: average with 7-day rolling average')
    ax.line(
        subStay.index,
        subStay.values,
        )
    ax.line(
        Data(rollingSubStay.index, label = 'Date'),
        Data(rollingSubStay.values, label = 'Proportion staying put'),
        )
    keystr = events_annotate(ax, subStay)
    display(ax.canvas.fig)

    ax = Canvas(size = (12, 3)).make_ax()
    ax.set_title('Stay-put score')
    ax.line(
        Data(subScore.index, label = 'Date'),
        Data(subScore.values, label = 'Stay-put score', lims = (-1., 2.)),
        )
    keystr = events_annotate(ax, subScore)
    display(ax.canvas.fig)

    ax = Canvas(size = (12, 3)).make_ax()
    ax.set_title('Daily active cases since the second wave')
    subCases = cases.xs(name, level = 'name')['active'].dropna()
    ax.line(
        Data(subCases.index, label = 'Date', lims = (subStay.index.min(), subStay.index.max())),
        Data(subCases.values, label = 'Active cases'),
        )
    display(ax.canvas.fig)

    markprint('---')

Breakdown by LGA

Bayside


Boroondara


Brimbank


Casey


Glen Eira


Greater Dandenong


Hume


Kingston


Maribyrnong


Melbourne


Moonee Valley


Moreland


Port Phillip


Stonnington


Yarra


In [ ]: